package com.mall.permission.init;

import com.mall.permission.model.Permission;
import com.mall.permission.service.IPermissionService;
import com.mall.permission.service.IRolePermissionService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author Darren
 * @date 2022-10-20 15:48
 * Description：
 */
@Component
public class InitPermission implements ApplicationRunner {
    @Autowired
    private IPermissionService permissionService;
    @Autowired
    private IRolePermissionService rolePermissionService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 初始化
     *
     * @param args
     * @throws Exception
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 根据匹配方式查找
        List<Permission> permissionMatch0 = permissionService.findByMatch(0);
        List<Permission> permissionMatch1 = permissionService.findByMatch(1);
        // 查询所有角色权限
        List<Map<String, String>> rolePermissions = rolePermissionService.allRolePermissions();

        // 角色权限处理
        Map<String, Set<Permission>> roleMap = this.rolePermissionFilter(rolePermissions, permissionMatch0, permissionMatch1);

        // 将所有权限和角色权限存入redis缓存
        redisTemplate.boundHashOps("RolePermissionAll").put("PermissionListMatch0", permissionMatch0);
        redisTemplate.boundHashOps("RolePermissionAll").put("PermissionListMatch1", permissionMatch1);
        redisTemplate.boundHashOps("RolePermissionMap").putAll(roleMap);

        // 存储权限uri到redis布隆过滤器中(先暂时做完全匹配的)
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("UriBloomFilterArray");
        // 必须要初始化数组长度和误判概率
        bloomFilter.tryInit(10000L, 0.001);
        // 添加到布隆过滤器
        permissionMatch0.forEach(m -> bloomFilter.add(m.getUrl()));
    }

    /**
     * 角色权限过滤
     *
     * @param rolePermissions  角色权限映射关系
     * @param permissionMatch0 所有完全匹配路径
     * @param permissionMatch1 所有通配符匹配路径
     * @return
     */
    public Map<String, Set<Permission>> rolePermissionFilter(List<Map<String, String>> rolePermissions,
                                                             List<Permission> permissionMatch0,
                                                             List<Permission> permissionMatch1) {
        // 角色权限关系,key=roleId,value=List<Permission>
        Map<String, Set<Permission>> rolePermissionMapping = new HashMap<>();

        // 关系循环处理
        for (Map<String, String> rolePermission : rolePermissions) {
            String rid = rolePermission.get("rid");
            String pid = rolePermission.get("pid");
            String key0 = "Role_0_" + rid;
            String key1 = "Role_1_" + rid;

            // 获取当前角色拥有的权限
            Set<Permission> permissionSet0 = rolePermissionMapping.get(key0);
            Set<Permission> permissionSet1 = rolePermissionMapping.get(key1);
            // 防止空指针
            if (permissionSet0 == null) permissionSet0 = new HashSet<>();
            if (permissionSet1 == null) permissionSet1 = new HashSet<>();

            // 循环完全匹配方式
            for (Permission permission : permissionMatch0) {
                if (pid.equals(permission.getId()))
                    permissionSet0.add(permission);
            }
            // 循环通配符匹配方式
            for (Permission permission : permissionMatch1) {
                if (pid.equals(permission.getId()))
                    permissionSet1.add(permission);
            }

            // 将数据添加到rolePermissionMapping中
            if (permissionSet0.size() > 0)
                rolePermissionMapping.put(key0, permissionSet0);
            if (permissionSet1.size() > 0)
                rolePermissionMapping.put(key1, permissionSet1);
        }

        return rolePermissionMapping;
    }
}
